Amazon Lex で2種類の会話ログの保存先と出力形式を確認してみた

Amazon Lex で2種類の会話ログの保存先と出力形式を確認してみた

Clock Icon2024.07.05

はじめに

Amazon Lexでは、2種類の会話ログを記録できます。

  • テキストログ(保存先:Amazon CloudWatch Logs)
  • 音声ログ(保存先:Amazon S3)

本記事では、各会話ログがどのようなプレフィックスやログストリーム名で保存されているかについて、AWSドキュメントに記載がないため、実際に確認してみます。

ログの確認には、テストケースとしてAmazon ConnectからLexを呼び出した際のログを使用します。

前提として、Amazon ConnectフローやLexボットは作成済みとします。

ログの有効化

Lexでの会話ログの有効化方法から説明します。

Lexのコンソール画面からボットを選択し、[エイリアス]からログの有効化ができます。

cm-hirai-screenshot 2024-07-03 17.37.40

テキストログはCloudWatch ロググループに、音声ログはS3バケットに保存できます。

ページ下部に記載されているように、ログを有効化すると、LexボットのIAMロールに必要な権限が自動的に適用されます。

cm-hirai-screenshot 2024-07-03 17.40.38

ログを有効化したLexボットのIAMロールを見ると、2つのIAMポリシーが自動で適用されていることが確認できました。

cm-hirai-screenshot 2024-07-03 17.45.30

各ログの保存先

それでは、Amazon ConnectからLexを呼び出すテストを実施した後、各会話ログの内容を確認します。

テキストログ(CloudWatch Logs)

ログストリーム名は以下形式で保存されます。

  • ログストリーム名:aws/lex/<LexボットID>/<エイリアスID>/<バージョン名>/<言語>/<ランダム文字列>
  • ログストリーム名の例:aws/lex/W2GNJPPTAK/TSTALIASID/DRAFT/ja_JP/00ca14cfe962f0a5651139a98c0c1b00

ログストリーム名には、コンタクトIDは入っていませんでした。

テスト時は、ログストリーム名の末尾がランダム文字列となるため、最終イベント時刻を参照してテストでのログ出力先を特定する必要があります。

cm-hirai-screenshot 2024-07-04 8.59.34

1度の通話(1つのコンタクトID)で、Lexインテント内の各スロットや確認プロンプトを利用した場合、または複数回Lexが起動した場合、同じコンタクトIDでログが保存されます。これにより、1つのログストリーム内に複数のログイベントとしてログが記録されます。

cm-hirai-screenshot 2024-07-04 10.15.18

ログイベント例
{
    "timestamp": "2024-07-03T23:04:06.323Z",
    "messages": [
        {
            "contentType": "PlainText",
            "content": "名字を教えて下さい"
        }
    ],
    "messageVersion": "2.0",
    "requestAttributes": {
        "x-amz-lex:accept-content-types": "PlainText,SSML",
        "x-amz-lex:channels:platform": "Connect"
    },
    "sessionId": "bb482df1-c0c3-41f5-a319-65cc3ef6a86d",
    "dialogEventLogs": [
        {
            "dialogStepLabel": "Intent/yes/Slot/last_name/Success",
            "nextStep": {
                "dialogAction": {
                    "type": "ElicitSlot",
                    "slotToElicit": "first_name"
                }
            }
        }
    ],
    "requestId": "0ef25491-2490-45f7-b250-aa19ca335036-ut-1",
    "isTestWorkbenchTraffic": false,
    "inputMode": "Speech",
    "bargeIn": "false",
    "operationName": "StartConversation",
    "interpretations": [
        {
            "nluConfidence": "1.00",
            "intent": {
                "name": "yes",
                "state": "InProgress",
                "confirmationState": "None",
                "slots": {
                    "last_name": {
                        "value": {
                            "originalValue": "ヒライデ",
                            "resolvedValues": [],
                            "interpretedValue": "ヒライデ"
                        },
                        "shape": "Scalar"
                    },
                    "first_name": null
                }
            },
            "interpretationSource": "Lex"
        },
        {
            "intent": {
                "name": "FallbackIntent",
                "slots": {}
            },
            "interpretationSource": "Lex"
        },
        {
            "nluConfidence": "0.35",
            "intent": {
                "name": "to",
                "slots": {}
            },
            "interpretationSource": "Lex"
        }
    ],
    "developerOverride": false,
    "bot": {
        "name": "cm-hirai-yes-or-no",
        "version": "DRAFT",
        "id": "W2GNJPPTAK",
        "aliasName": "TestBotAlias",
        "aliasId": "TSTALIASID",
        "localeId": "ja_JP"
    },
    "sessionState": {
        "sessionAttributes": {},
        "intent": {
            "name": "yes",
            "state": "InProgress",
            "confirmationState": "None",
            "slots": {
                "last_name": {
                    "value": {
                        "originalValue": "ヒライデ",
                        "resolvedValues": [],
                        "interpretedValue": "ヒライデ"
                    },
                    "shape": "Scalar"
                },
                "first_name": null
            }
        },
        "dialogAction": {
            "type": "ElicitSlot",
            "slotToElicit": "first_name"
        },
        "originatingRequestId": "0ef25491-2490-45f7-b250-aa19ca335036"
    },
    "inputTranscript": "ヒライデ",
    "missedUtterance": false,
    "audioProperties": {
        "contentType": "audio/lpcm; sample-rate=8000; sample-size-bits=16; channel-count=1; is-big-endian=false",
        "duration": {
            "total": 2213,
            "silence": 1323,
            "voice": 890
        },
        "s3Path": "cm-hirai-connect-lex-recordings/aws/lex/W2GNJPPTAK/TSTALIASID/DRAFT/ja_JP/bb482df1-c0c3-41f5-a319-65cc3ef6a86d/0ef25491-2490-45f7-b250-aa19ca335036-ut-1.wav"
    },
    "utteranceContext": {}
}

一部のプロパティを解説します。

  • s3Pathは、オーディオログとしてS3バケットに保存されるパスが確認できます。
  • sessionIdは、コンタクトIDの値です。
  • originatingRequestIdは、Connectフロー内でLexが呼び出される度に作成されるランダム文字列のIDです。通話中、ConnectフローからLexが呼び出される度に、IDは変わります。呼び出されたLex内の各スロットや確認プロンプトでは同じIDになります。
    • 0ef25491-2490-45f7-b250-aa19ca335036
  • requestIdは、originatingRequestIdに連番がついたIDです。呼び出されたLex内の各スロットや確認プロンプトでは、同じoriginatingRequestIdに連番が付与されます。
    • 0ef25491-2490-45f7-b250-aa19ca335036-ut-0
    • 0ef25491-2490-45f7-b250-aa19ca335036-ut-1
    • 0ef25491-2490-45f7-b250-aa19ca335036-ut-2

他の各プロパティは、以下のドキュメントでご確認ください。

https://docs.aws.amazon.com/ja_jp/lexv2/latest/dg/conversation-logs-cw.html

音声ログ(S3バケット)

S3 URIは以下の形式で保存されます。

  • S3 URI:s3://バケット名/aws/lex/<LexボットID>/<エイリアスID>/<バージョン名>/<言語>/<sessionId>(コンタクトID)/<requestId>.wav
  • S3 URI例:s3://cm-hirai-connect-lex-recordings/aws/lex/W2GNJPPTAK/TSTALIASID/DRAFT/ja_JP/bb482df1-c0c3-41f5-a319-65cc3ef6a86d/0ef25491-2490-45f7-b250-aa19ca335036-ut-0.wav
    • コンソールのS3バケットの<sessionId>(コンタクトID)URL例:https://ap-northeast-1.console.aws.amazon.com/s3/buckets/cm-hirai-connect-lex-recordings?region=ap-northeast-1&bucketType=general&prefix=aws/lex/W2GNJPPTAK/TSTALIASID/DRAFT/ja_JP/bb482df1-c0c3-41f5-a319-65cc3ef6a86d/&showversions=false
    • コンソールのS3バケットの音声ファイルURL例:https://ap-northeast-1.console.aws.amazon.com/s3/object/cm-hirai-connect-lex-recordings?region=ap-northeast-1&bucketType=general&prefix=aws/lex/W2GNJPPTAK/TSTALIASID/DRAFT/ja_JP/bb482df1-c0c3-41f5-a319-65cc3ef6a86d/0ef25491-2490-45f7-b250-aa19ca335036-ut-0.wav

requestIdは、CloudWatch Logsのテキストログで出力されます。また、Connectから呼ばれたLexにおいて、インテント内の各スロットや確認プロンプトなど複数回やりとりした場合、コンタクトIDが同じですので、以下の通りのrequestIdは連番となります。

  • 0ef25491-2490-45f7-b250-aa19ca335036-ut-0
  • 0ef25491-2490-45f7-b250-aa19ca335036-ut-1
  • 0ef25491-2490-45f7-b250-aa19ca335036-ut-2

cm-hirai-screenshot 2024-07-04 8.43.41

1度の通話で、Lexインテント内の各スロットや確認プロンプトを利用した場合、または、複数回Lexが起動した場合、同じコンタクトIDで音声ファイルが保存されますので、1つのsessionId(コンタクトID)配下に複数の音声ファイルが保存されます。

cm-hirai-screenshot 2024-07-04 8.23.45

CloudWatch Logsとは異なり、S3バケット内ではコンタクトIDごとに更新時間でソートすることができません。そのため、テスト時の音声ログを確認するには以下の手順が必要となります:

  1. CloudWatch LogsのテキストログからsessionId(コンタクトID)とrequestIdを確認する
  2. 確認した情報をもとに、S3バケット内のテスト時の音声ログファイルを検索する

プレフィックス

ドキュメントに記載されていますが、S3バケット および CloudWatch LogsのPrefix値は、API経由で設定できます。

https://docs.aws.amazon.com/ja_jp/lexv2/latest/APIReference/API_CreateBotAlias.html

~略~
   "conversationLogSettings": { 
      "audioLogSettings": [ 
         { 
            "destination": { 
               "s3Bucket": { 
                  "kmsKeyArn": "string",
                  "logPrefix": "string",
                  "s3BucketArn": "string"
               }
            },
            "enabled": boolean,
            "selectiveLoggingEnabled": boolean
         }
      ],
      "textLogSettings": [ 
         { 
            "destination": { 
               "cloudWatch": { 
                  "cloudWatchLogGroupArn": "string",
                  "logPrefix": "string"
               }
            },
            "enabled": boolean,
            "selectiveLoggingEnabled": boolean
         }
      ]
   },

最後に

今回は、Amazon Lexの会話ログであるテキストログと音声ログの保存先と形式について詳しく解説しました。

これらの会話ログを適切に活用することで、チャットボットの認識精度向上や応答品質の改善でき、ユーザー体験の向上につながります。

本記事が参考になれば幸いです。

参考

https://docs.aws.amazon.com/ja_jp/lexv2/latest/dg/enabling-logs.html

この記事をシェアする

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.